package com.cooper.service.core;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cooper.entity.EmailServerSetting;
import com.google.common.base.Splitter;

/**
 * 用于发送接收邮件
* @Description: 
* @version: v1.0.0
* @author: coral coraldane@163.com
* @date: Jan 29, 2015 10:31:46 PM
*
* Modification History:
*  Date              Author          Version            Description
*-------------------------------------------------------------------*
* Jan 29, 2015      coraldane        v1.0.0
 */
@Service
public class EmailExecutor {
	private static final Logger logger = LoggerFactory.getLogger(EmailExecutor.class);
	private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
	
	@Autowired
	private EmailSettingService emailSettingService;
	
	private EmailServerSetting serverSetting = null;
	private String userName = null;
	private String userPassword = null;
	private String from = null;
	private String displayName;
	
	public EmailExecutor(){
		
	}
	
	public void init(String from, String displayName, String userPassword){
		this.from = from;
		this.displayName = displayName;
		this.userName = from.substring(0, from.indexOf("@"));
		this.userPassword = userPassword;
		if(isEmail(from)){
			String emailType = this.getEmailType(from);
			this.setServerSetting(emailType);
		}
	}
	
	public static boolean isEmail(String text){
		return Pattern.compile("^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$").matcher(text).matches();
	}
	
	private String getEmailType(String from) {
		int pos = from.indexOf("@");
		if(pos > 0){
			return from.substring(pos+1);
		}else{
			return null;
		}
	}
	
	private EmailServerSetting getServerSetting(String emailType){
		EmailServerSetting setting = null;
		try{
			setting = emailSettingService.getSetting(emailType);
			if(null == setting){
				setting = new EmailServerSetting();
				setting.setEmailType(emailType);
				setting.setPopServer("pop." + emailType);
				setting.setPopPort(110);
				setting.setSmtpServer("smtp." + emailType);
				setting.setSmtpPort(25);
				setting.setAuthorized(1);
				setting.setAdministrator(0);
				this.emailSettingService.saveEntity(setting);
			}
		} catch (Exception e){
			logger.error("Can't get server setting for [" + emailType + "]", e);
		}
		return setting;
	}
	
	public void send(String to, String subject, String content) throws Exception{
		List<String> toList = Splitter.on(",").splitToList(to);
		this.send(toList, null, null, subject, content, null);
	}
	
	/**
	 * 发送邮件主体
	 * @param toList 收件人列表
	 * @param ccList 抄送收件人列表
	 * @param bccList 暗送收件人列表
	 * @param subject 邮件标题
	 * @param content 邮件内容，正文
	 * @param attachmentMap 附件路径列表
	 * @throws Exception
	 * @date Apr 17, 2012 3:10:32 PM
	 * @author coral
	 */
	public void send(List<String> toList, List<String> ccList, List<String> bccList, 
			String subject, String content, Map<String, byte[]> attachmentMap)
		throws Exception{
		if(null == this.serverSetting){
			logger.warn("Sorry, The Email executor doesn't support this mail at all.");
			return;
		}
		Properties props = new Properties();
		props.put("mail.smtp.host", this.serverSetting.getSmtpServer());
		props.put("mail.smtp.port", this.serverSetting.getSmtpPort());
		//props.put("mail.debug", true);
		if(1 == this.serverSetting.getIsSsl()){
			java.security.Security.setProperty("ssl.SocketFactory.provider", "sun.security.ssl.SSLSocketFactoryImpl");
			java.security.Security.setProperty("ssl.ServerSocketFactory.provider", "sun.security.ssl.SSLSocketFactoryImpl");
			props.put("mail.smtp.socketFactory.port", this.serverSetting.getSmtpPort());
			props.put("mail.smtp.socketFactory.class", SSL_FACTORY);
	        props.put("mail.smtp.socketFactory.fallback","false");
		}
		
		Session session = null;
		props.put("mail.smtp.auth", "true");
		session = Session.getDefaultInstance(props, new Authenticator(){
			protected PasswordAuthentication getPasswordAuthentication(){
				logger.debug("Email Authronize for " + userName + "," + userPassword);
				return new PasswordAuthentication(userName, userPassword);
			}
		});
		session.setDebug(true);
		Message msg = new MimeMessage(session);
		msg.setFrom(new InternetAddress(from, this.displayName));
		
		InternetAddress[] toAddress= new InternetAddress[toList.size()];
		for(int i=0; i<toList.size();i++){
			toAddress[i]= new InternetAddress(toList.get(i).toString());
		}
		msg.addRecipients(Message.RecipientType.TO, toAddress);
		
		if(null != ccList){
			InternetAddress[] ccAddress= new InternetAddress[ccList.size()];
			for(int i=0; i< ccList.size();i++){
				ccAddress[i]= new InternetAddress(ccList.get(i).toString());
			}
			msg.addRecipients(Message.RecipientType.CC, ccAddress);
		}
		
		if(null != bccList){
			InternetAddress[] bccAddress= new InternetAddress[bccList.size()];
			for(int i=0; i< bccList.size();i++){
				bccAddress[i]= new InternetAddress(bccList.get(i).toString());
			}
			msg.addRecipients(Message.RecipientType.BCC, bccAddress);
		}
		
		msg.setSubject(subject);
		Multipart multipart = new MimeMultipart();
		BodyPart contentPart = new MimeBodyPart();
		contentPart.setContent(content, "text/html;charset=UTF-8");
		multipart.addBodyPart(contentPart);
		
		if(null != attachmentMap && !attachmentMap.isEmpty()){
			for(Iterator<String> iter = attachmentMap.keySet().iterator(); iter.hasNext();){
				String fileName = iter.next();
				BodyPart attachmentBodyPart = new MimeBodyPart();
				ByteArrayDataSource source = new ByteArrayDataSource(attachmentMap.get(fileName), "application/octet-stream");
				attachmentBodyPart.setDataHandler(new DataHandler(source));
				if(StringUtils.isEmpty(fileName)){
					fileName = source.getName();
				}
				attachmentBodyPart.setFileName(MimeUtility.encodeText(fileName));
				multipart.addBodyPart(attachmentBodyPart);
			}
		}
		msg.setContent(multipart);
		msg.saveChanges();
//		msg.setContent(content, "text/html;charset=UTF-8");
		Transport.send(msg);
//		Transport tran = session.getTransport("smtp");
//		tran.connect(this.smtpServer, this.userName, this.userPassword);
//		tran.sendMessage(msg, msg.getAllRecipients());
	}
	
	public String getDisplayName() {
		return displayName;
	}
	public void setDisplayName(String displayName) {
		this.displayName = displayName;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getUserPassword() {
		return userPassword;
	}
	public void setUserPassword(String userPassword) {
		this.userPassword = userPassword;
	}

	public String getFrom() {
		return from;
	}

	public void setFrom(String from) {
		this.from = from;
	}

	public EmailServerSetting getServerSetting() {
		return serverSetting;
	}

	public void setServerSetting(EmailServerSetting serverSetting) {
		this.serverSetting = serverSetting;
	}
	
	public void setServerSetting(String emailType){
		this.serverSetting = this.getServerSetting(emailType);
	}

	public EmailSettingService getEmailSettingService() {
		return emailSettingService;
	}

	public void setEmailSettingService(EmailSettingService emailSettingService) {
		this.emailSettingService = emailSettingService;
	}

}
